package com.phenix.mvp.base;


import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.SparseArray;

import com.orhanobut.logger.Logger;
import com.phenix.annotation.javassist.Bus;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class OkBus<T> {
    private static final String TAG = OkBus.class.getSimpleName();

    //存储所有事件ID以及其回调
    private volatile SparseArray<List<SparseArray<Event>>> mEvents = new SparseArray<>();

    //存储粘连事件ID以及其数据
    private volatile SparseArray<Object> mStickyEvents = new SparseArray<>();

    private  static ScheduledExecutorService mScheduledPool = Executors.newScheduledThreadPool(5);

    private static Handler mHandler = new Handler(Looper.getMainLooper());


    private OkBus(){}

    private static class Holder{
        static final OkBus mInstance = new OkBus();
    }

    public static OkBus getInstance(){
        return Holder.mInstance;
    }

    public OkBus register(int tag, Event event){
        register(tag, event, Bus.DEFAULT);
        return this;
    }

    public OkBus register(int tag, final Event event, int thread){
        SparseArray<Event> events = new SparseArray<>();
        events.put(thread,event);
        if (null != mEvents.get(tag)){
            mEvents.get(tag).add(events);
        }else{
            List<SparseArray<Event>> list = new ArrayList<>();
            list.add(events);
            mEvents.put(tag, list);
        }
        Logger.t(TAG).d("Bus register >>>tag=" + tag + " >>>events.size=" + mEvents.get(tag).size());
        if (null != mStickyEvents.get(tag)) {//注册时分发粘连事件
            final Message message = mHandler.obtainMessage();
            message.obj = mStickyEvents.get(tag);
            message.what = tag;
            callEvent(message, event, thread);
            Logger.t(TAG).d("mStickyEvents register  and  onEvent>>>tag=" + tag + " >>>events.size=" + mEvents.get(tag).size());
        }


        return this;
    }

    private void callEvent(final Message message, Event event, int thread) {
        switch (thread){
            case Bus.DEFAULT:
                event.call(message);
                break;
            case Bus.UI:
                mHandler.post(()->event.call(message));
                break;
            case Bus.BG:
                mScheduledPool.execute(()->event.call(message));
                break;
        }

    }

    public OkBus unregister(int tag){
        if (null != mEvents.get(tag)) mEvents.remove(tag);
        return this;
    }

    public OkBus onEvent(int tag, T data){
        if (null != mEvents.get(tag)){
            Message message = mHandler.obtainMessage();
            message.obj = data;
            message.what = tag;
            Logger.t(TAG).d("Bus onEvent >>>tag=" + tag + " >>>events.size=" + mEvents.get(tag).size());
            for(SparseArray<Event> events : mEvents.get(tag)){
                callEvent(message, events.valueAt(0), events.keyAt(0));
            }
        }
        return this;
    }


    public OkBus onStickyEvent(int tag, T data){
        Logger.t(TAG).d("Bus onStickyEvent >>>tag=" + tag + " ");
        mStickyEvents.put(tag, (data == null ? tag : data));
        onEvent(tag, data);
        return this;
    }


}
